﻿using UnityEngine;
using System.Collections;

public class GridManager {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}

    private static GridManager Instance;
    public static GridManager getInstace()
    {
        if (GridManager.Instance == null)
        {
            GridManager.Instance = new GridManager();
        }
        return GridManager.Instance;
    }

    private GridManager() { }


    public int map_width = 2000;
    public int map_height = 2000;
    public int grid_size = 20;

    public ASNode[,] gridArray;

    private Vector3 origin;
    public Vector3 Origin
    {
        get { return origin; }
    }

    public void Initialiaze(Vector3 origin,int map_width,int map_height,int grid_size)//cast the map to a 2 dimensionality array;
    {
        this.origin = origin;
        this.map_width = map_width;
        this.map_height = map_height;
        this.grid_size = grid_size;

        //inilize all grid
        int mapWidthCount = map_width/grid_size;
        int mapHeightCount = map_height/grid_size;

        gridArray = new ASNode[mapWidthCount,mapHeightCount];

        for (int i = 0; i < mapWidthCount; i++)
        {
            for (int j = 0; j < mapHeightCount; j++)
            {
                ASNode tempNode = new ASNode(this.getPositionByIndexXY(i, j));
                gridArray[i,j] = tempNode;
            }
        }

        ArrayList obstacleLst = ObstacleManager.Instance().getObstacle();

        foreach (var item in obstacleLst)
        {
            Vector3 tempPosition = ((GameObject)item).transform.position;
            if (this.isBounds(tempPosition))
            {
                Vector2 tempIndexXY = this.getIndexXYByPosition(tempPosition);
                int x = (int)tempIndexXY.x;
                int y = (int)tempIndexXY.y;
                gridArray[x, y].isObstacle = true;
            }  
        }

    }

    public Vector3 getPositionByIndexXY(int x,int y)
    {
        Vector3 temp = Vector3.zero;
        temp.x = Origin.x + x * grid_size;
        temp.y = Origin.y + y * grid_size;

        return temp;
    }

    public Vector2 getIndexXYByPosition(Vector3 position)
    {
        Vector2 temp = Vector2.zero;

        float distanceX = position.x - Origin.x;
        float absDistanceX = Mathf.Abs(distanceX);
        float factorX = absDistanceX / grid_size;
        if (factorX - 0.5 <= 0)
        {
            temp.x = 0;
        }
        else
        {
            temp.x = Mathf.Ceil((float)(factorX - 0.5));
        }
        if (distanceX < 0)
        {
            temp.x = -temp.x;
        }

        float distanceY = position.y - Origin.y;
        float absDistanceY = Mathf.Abs(distanceY);
        float factorY = absDistanceY / grid_size;
        if (factorY - 0.5 <= 0)
        {
            temp.y = 0;
        }
        else
        {
            temp.y = Mathf.Ceil((float)(factorY - 0.5));
        }
        if (distanceY < 0)
        {
            temp.y = -temp.y;
        }

        return temp;
    }

    public ASNode getNodeByPosition(Vector3 position)
    {
        Vector2 index = getIndexXYByPosition(position);
        return gridArray[(int)index.x,(int)index.y];
    }

    public bool isBounds(Vector3 position)
    {
        Vector2 indexXY = this.getIndexXYByPosition(position);
        int x = (int)indexXY.x;
        int y = (int)indexXY.y;

        int mapWidthCount = map_width/grid_size;
        int mapHeightCount = map_height/grid_size;

        return !((x >= mapWidthCount) || (y >= mapHeightCount) || (x < 0) || (y < 0));
    }

    public ArrayList getNeighbourNodes(ASNode node)
    {
        ArrayList neighbours = new ArrayList();

        Vector3 node_postion = node.position;
        Vector2 indexXY = this.getIndexXYByPosition(node_postion);

        //left_node
        Vector2 indexXY_left = new Vector2(indexXY.x - 1, indexXY.y);
        ASNode tempNode = mathNodeByIndexXY(indexXY_left);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_left_bottom = new Vector2(indexXY.x - 1, indexXY.y + 1);
        tempNode = mathNodeByIndexXY(indexXY_left_bottom);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_bottom = new Vector2(indexXY.x, indexXY.y + 1);
        tempNode = mathNodeByIndexXY(indexXY_bottom);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_bottom_right = new Vector2(indexXY.x + 1, indexXY.y + 1);
        tempNode = mathNodeByIndexXY(indexXY_bottom_right);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_right = new Vector2(indexXY.x + 1, indexXY.y);
        tempNode = mathNodeByIndexXY(indexXY_right);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 idnexXY_right_top = new Vector2(indexXY.x + 1, indexXY.y - 1);
        tempNode = mathNodeByIndexXY(idnexXY_right_top);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_top = new Vector2(indexXY.x, indexXY.y - 1);
        tempNode = mathNodeByIndexXY(indexXY_top);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }

        Vector2 indexXY_top_left = new Vector2(indexXY.x - 1, indexXY.y - 1);
        tempNode = mathNodeByIndexXY(indexXY_top_left);
        if (tempNode != null)
        {
            neighbours.Add(tempNode);
        }


        return neighbours;
    }

    public ASNode mathNodeByIndexXY(Vector2 indexXY)
    {
        int x = (int)indexXY.x;
        int y = (int)indexXY.y;

        int mapWidthCount = map_width / grid_size;
        int mapHeightCount = map_height / grid_size;
        bool is_in_bounds = !((x >= mapWidthCount) || (y >= mapHeightCount) || (x < 0) || (y < 0));

        if (is_in_bounds == true)
        {
            ASNode node = gridArray[x, y];
            if (node.isObstacle == false)
            {
                return node;
            }
        }

        return null;
        
    }
    public bool ANodeEqualToBNode(ASNode A, ASNode B)
    {
        Vector2 indexA = getIndexXYByPosition(A.position);
        Vector2 indexB = getIndexXYByPosition(B.position);

        return (int)indexA.x == (int)indexB.x && (int)indexA.y == (int)indexB.y;
    }
}
